﻿#include "RtspClient.h"
#include <WS2tcpip.h>
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")
#include "Sdp.h"
#include "Log.h"

RtspClient::RtspClient(const char* transport, const char* url):
	m_userAgent("BXC_RtspClient"),
	m_transport(transport),
	m_rtspUrl(url){

	LOGI("");

	char ip[40] = { 0 };
	uint16_t port = 0;
	char mediaRoute[100] = { 0 };

	WSADATA wsaData;
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
	{
		LOGE("WSAStartup error");
	}

	if (strncmp(url, "rtsp://", 7) != 0) {
		LOGE("parse Url protocol error");
	}
	if (sscanf(url + 7, "%[^:]:%hu/%s", ip, &port, mediaRoute) == 3) {
	}
	else if (sscanf(url + 7, "%[^/]/%s", ip, mediaRoute) == 2) {
	}
	else {
		LOGE("parse Url compontent error");
	}
	m_ip = ip;
	m_port = port;
	m_mediaRoute = mediaRoute;
	m_sdp = new Sdp;
}

RtspClient::~RtspClient()
{
	LOGI("");
	closesocket(m_fd);
	WSACleanup();

	if (m_sdp) {
		delete m_sdp;
		m_sdp = nullptr;
	}
}

bool RtspClient::connectServer() {
	LOGI("RtspClient::connectServer：rtspUrl=%s", m_rtspUrl.data());

	m_fd = socket(AF_INET, SOCK_STREAM, 0);
	if (m_fd < 0)
	{
		LOGE("create socket error");
		return false;
	}

	int on = 1;
	setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on));

	sockaddr_in client_addr;
	client_addr.sin_family = AF_INET;
	client_addr.sin_addr.S_un.S_addr = INADDR_ANY;

	if (bind(m_fd, (LPSOCKADDR)&client_addr, sizeof(SOCKADDR)) == -1)
	{
		LOGE("bind error");
		return false;
	}
	struct sockaddr_in m_server_addr;
	m_server_addr.sin_family = AF_INET;
	m_server_addr.sin_port = htons(m_port);
	inet_pton(AF_INET, m_ip.c_str(), &m_server_addr.sin_addr);


	if (connect(m_fd, (struct sockaddr*)&m_server_addr, sizeof(sockaddr_in)) == -1)
	{
		LOGE("connect error %d", WSAGetLastError());
		return false;
	}

	return true;
}

void RtspClient::startCmd() {

	bool isSendPlay = false;
	int sendCseq = 0; // 与RTSP服务交互过程中Seq的累计值
	int sendTrackNum = 0;

	// RTSP协议交互每次返回的参数解析 start
	int  CSeq = 0;
	char sessionID[50] = { 0 };//从Rtsp响应中获取Session
	int  ResponseStateCode = 0;
	int  ContentLength = 0;
	char ContentBase[100] = { 0 };

	char bufCmdRecv[1000] = { 0 };
	char bufCmdRecvCopy[1000] = { 0 };
	int  bufCmdRecvSize = 0;
	// RTSP协议交互每次返回的参数解析 end


	++sendCseq;
	if (!sendCmdOptions(sendCseq)) {
		return;
	}
	while (true)
	{
		ResponseStateCode = 0;
		CSeq = 0;
		ContentLength = 0;

		bufCmdRecvSize = recv(m_fd, bufCmdRecv,sizeof(bufCmdRecv), 0);
		if (bufCmdRecvSize <= 0) {
			LOGE("bufCmdRecv error: %d", WSAGetLastError());
			goto FINISH;
		}

		memcpy(bufCmdRecvCopy, bufCmdRecv, bufCmdRecvSize);
		bufCmdRecv[bufCmdRecvSize] = '\0';
		bufCmdRecvCopy[bufCmdRecvSize] = '\0';

		LOGI("bufCmdRecvSize=%d,bufCmdRecv=%s", bufCmdRecvSize, bufCmdRecv);

		const char* sep = "\n";
		char* line = strtok(bufCmdRecv, sep);
		while (line) {
			if (strstr(line, "RTSP/1.0")) {
				if (sscanf(line, "RTSP/1.0 %d OK\r\n", &ResponseStateCode) != 1) {
					LOGE("parse RTSP/1.0 error");
					goto FINISH;
				}
			}
			else if (strstr(line, "Session")) {

				//memset(sessionID, 0, sizeof(sessionID) / sizeof(char));
				if (sscanf(line, "Session: %s\r\n", &sessionID) != 1) {
					LOGE("parse Session error");
					goto FINISH;
				}
				else {
					m_sessionID = sessionID;

				}
			}
			else if (strstr(line, "CSeq")) {
				if (sscanf(line, "CSeq: %d\r\n", &CSeq) != 1) {
					LOGE("parse CSeq error");
					goto FINISH;
				}
			}
			else if (strstr(line, "Content-Base")) {
				if (sscanf(line, "Content-Base: %s\r\n", &ContentBase) != 1) {
					LOGE("parse Content-Base error");
					goto FINISH;
				}

			}
			else if (strstr(line, "Content-length")) {
				if (sscanf(line, "Content-length: %d\r\n", &ContentLength) != 1) {
					LOGE("parse Content-length error");
					goto FINISH;
				}

			}
			else if (strstr(line, "Content-Length")) {
				if (sscanf(line, "Content-Length: %d\r\n", &ContentLength) != 1) {
					LOGE("parse Content-Length error");
					goto FINISH;
				}

			}
			line = strtok(NULL, sep);
		}

		if (200 == ResponseStateCode) {

			if (1 == CSeq) {
				// 解析Options，发送Describe
				++sendCseq;
				if (!sendCmdDescribe(sendCseq)) {
					goto FINISH;
				}
			}
			else if (2 == CSeq)
			{
				// 解析Sdp
				m_sdp->parse(bufCmdRecvCopy, bufCmdRecvSize);

				// 发送Setup请求
				SdpTrack* track = m_sdp->popTrack();
				if (track) {
					++sendCseq;
					++sendTrackNum;
					sendCmdSetup(sendCseq, track);

				}

			}
			else if (sendCseq == CSeq && !isSendPlay) {
				// 继续发送Setup请求
				SdpTrack* track = m_sdp->popTrack();
				if (track) {
					++sendCseq;
					++sendTrackNum;
					sendCmdSetup(sendCseq, track);
				}else {
					LOGI("发送(%d次)track完成，开始发送Play请求",sendTrackNum);

					++sendCseq;
					if (!sendCmdPlay(sendCseq)) {
						goto FINISH;
					}
					isSendPlay = true;

				}
			}
			else if (sendCseq == CSeq && isSendPlay) {
				LOGI("接收到Play请求的响应");
				parseData();
				goto FINISH;
			}
			else {

				LOGE("CSeq=%d is error", CSeq);
				goto FINISH;
			}


		}
		else {
			LOGE("Rtsp ResponseStateCode=%d is error", ResponseStateCode);
			goto FINISH;
		}

	}

FINISH:
	return;

}
bool RtspClient::sendCmdOptions(int cseq) {

	sprintf(m_bufSnd, "OPTIONS rtsp://%s:%d/%s RTSP/1.0\r\n"
		"CSeq: %d\r\n"
		"User-Agent: %s\r\n"
		"\r\n",
		m_ip.data(),m_port,m_mediaRoute.data(),
		cseq,
		m_userAgent.data());

	return sendCmdOverTcp(m_bufSnd, strlen(m_bufSnd));
}
bool RtspClient::sendCmdDescribe(int cseq) {

	sprintf(m_bufSnd, "DESCRIBE rtsp://%s:%d/%s RTSP/1.0\r\n"
		"Accept: application/sdp\r\n"
		"CSeq: %d\r\n"
		"User-Agent: %s\r\n"
		"\r\n",
		m_ip.data(),m_port,m_mediaRoute.data(),
		cseq,
		m_userAgent.data());

	return sendCmdOverTcp(m_bufSnd, strlen(m_bufSnd));
}
bool RtspClient::sendCmdSetup(int cseq, SdpTrack* track) {
	int interleaved1 = track->control_id * 2;
	int interleaved2 = interleaved1 + 1;


	sprintf(m_bufSnd, "SETUP rtsp://%s:%d/%s/%s RTSP/1.0\r\n"
		"Transport: RTP/AVP/TCP;unicast;interleaved=%d-%d\r\n"
		"CSeq: %d\r\n"
		"User-Agent: %s\r\n"
		"Session: %s\r\n"
		"\r\n",
		m_ip.data(),m_port, m_mediaRoute.data(), track->control,
		interleaved1,interleaved2,
		cseq,
		m_userAgent.data(),
		m_sessionID.data());

	return sendCmdOverTcp(m_bufSnd, strlen(m_bufSnd));
}

bool RtspClient::sendCmdPlay(int cseq) {

	sprintf(m_bufSnd, "PLAY rtsp://%s:%d/%s RTSP/1.0\r\n"
		"Range: npt=0.000-\r\n"
		"CSeq: %d\r\n"
		"User-Agent: %s\r\n"
		"Session: %s\r\n"
		"\r\n",
		m_ip.data(),m_port,m_mediaRoute.data(),
		cseq,
		m_userAgent.data(),
		m_sessionID.data());

	return sendCmdOverTcp(m_bufSnd, strlen(m_bufSnd));
}
bool RtspClient::sendCmdOverTcp(char* buf, size_t size) {
	printf("\n\n---------------------------------------\n\n");

	LOGI("size=%lld,buf=%s", size,buf);

	int ret = send(m_fd, buf, size, 0);

	if (ret < 0) {
		LOGE("send error: %d", WSAGetLastError());
		return false;
	}
	return true;
}

void RtspClient::parseData() {
	char bufRecv[1000];
	int  bufRecvSize = 0;

	while (true)
	{
		bufRecvSize = recv(m_fd, bufRecv, sizeof(bufRecv), 0);

		if (bufRecvSize <= 0) {
			LOGE("parseData recv error: %d", WSAGetLastError());
			break;
		}
		else {
			//LOGI("parseData bufRecvSize=%d", bufRecvSize);

		}
	}


}
